package com.webex.ta.hydra.gui.util;

import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.*;

/**
 * Author: Vegaz
 * Date: 2010-11-22
 * Time: 16:37:34
 */
public class ListScrollingUtil {
    public static final int ROW_PADDING = 2;

    public static void moveDown(JList list, final int modifiers) {
        int size = list.getModel().getSize();
        if (size == 0) {
            return;
        }
        final ListSelectionModel selectionModel = list.getSelectionModel();
        int index = selectionModel.getLeadSelectionIndex();
        boolean cycleScrolling = true;
        final int indexToSelect;
        if (index < size - 1) {
            indexToSelect = index + 1;
        } else if (cycleScrolling && index == size - 1) {
            indexToSelect = 0;
        } else {
            return;
        }
        ensureIndexIsVisible(list, indexToSelect, +1);
        if (selectionModel.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
            selectionModel.setSelectionInterval(indexToSelect, indexToSelect);
        } else {
            if ((modifiers & InputEvent.SHIFT_DOWN_MASK) == 0) {
                selectionModel.removeSelectionInterval(selectionModel.getMinSelectionIndex(), selectionModel.getMaxSelectionIndex());
            }
            selectionModel.addSelectionInterval(indexToSelect, indexToSelect);
        }
    }

    public static void moveUp(JList list, int modifiers) {
        int size = list.getModel().getSize();
        final ListSelectionModel selectionModel = list.getSelectionModel();
        int index = selectionModel.getMinSelectionIndex();
        boolean cycleScrolling = true;
        int indexToSelect;
        if (index > 0) {
            indexToSelect = index - 1;
        } else if (cycleScrolling && index == 0) {
            indexToSelect = size - 1;
        } else {
            return;
        }
        ensureIndexIsVisible(list, indexToSelect, -1);
        if (selectionModel.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
            selectionModel.setSelectionInterval(indexToSelect, indexToSelect);
        } else {
            if ((modifiers & InputEvent.SHIFT_DOWN_MASK) == 0) {
                selectionModel.removeSelectionInterval(selectionModel.getMinSelectionIndex(), selectionModel.getMaxSelectionIndex());
            }
            selectionModel.addSelectionInterval(indexToSelect, indexToSelect);
        }
    }


    public static void movePageUp(JList list) {
        int visible = getVisibleRowCount(list);
        ListSelectionModel selectionModel = list.getSelectionModel();
        if (visible <= 0) {
            moveHome(list);
            return;
        }
        int size = list.getModel().getSize();
        int decrement = visible - 1;
        int index = Math.max(list.getSelectedIndex() - decrement, 0);
        int top = list.getFirstVisibleIndex() - decrement;
        if (top < 0) {
            top = 0;
        }
        int bottom = top + visible - 1;
        if (bottom >= size) {
            bottom = size - 1;
        }
        //list.clearSelection();
        Rectangle cellBounds = list.getCellBounds(top, bottom);
        if (cellBounds == null) {
            moveHome(list);
            return;
        }
        list.scrollRectToVisible(cellBounds);
        selectionModel.setSelectionInterval(index, index);
        list.ensureIndexIsVisible(index);
    }


    public static void movePageDown(JList list) {
        int visible = getVisibleRowCount(list);
        if (visible <= 0) {
            moveEnd(list);
            return;
        }
        int size = list.getModel().getSize();
        int increment = visible - 1;
        int index = Math.min(list.getSelectedIndex() + increment, size - 1);
        int top = list.getFirstVisibleIndex() + increment;
        int bottom = top + visible - 1;
        if (bottom >= size) {
            bottom = size - 1;
        }
        //list.clearSelection();
        Rectangle cellBounds = list.getCellBounds(top, bottom);
        if (cellBounds == null) {
            moveEnd(list);
            return;
        }
        list.scrollRectToVisible(cellBounds);
        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
    }


    public static void ensureIndexIsVisible(JList list, int index, int moveDirection) {
        int visible = getVisibleRowCount(list);
        int size = list.getModel().getSize();
        int top;
        int bottom;
        if (moveDirection == 0) {
            top = index - (visible - 1) / ROW_PADDING;
            bottom = top + visible - 1;
        } else if (moveDirection < 0) {
            top = index - ROW_PADDING;
            bottom = index;
        } else {
            top = index;
            bottom = index + ROW_PADDING;
        }
        if (top < 0) {
            top = 0;
        }
        if (bottom >= size) {
            bottom = size - 1;
        }
        Rectangle cellBounds = list.getCellBounds(top, bottom);
        if (cellBounds != null) {
            cellBounds.x = 0;
            list.scrollRectToVisible(cellBounds);
        }
    }

    public static void moveHome(JList list) {
        list.setSelectedIndex(0);
        list.ensureIndexIsVisible(0);
    }

    public static void moveEnd(JList list) {
        int index = list.getModel().getSize() - 1;
        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
    }

    public static boolean selectItem(JList list, Object item) {
        ListModel model = list.getModel();
        for (int i = 0; i < model.getSize(); i++) {
            Object anItem = model.getElementAt(i);
            if (item.equals(anItem)) {
                selectItem(list, i);
                return true;
            }
        }
        return false;
    }

    private static int getVisibleRowCount(JList list) {
        return list.getLastVisibleIndex() - list.getFirstVisibleIndex() + 1;
    }
}
